package com.littlerpc.common.util;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


/**
 * Created by ChengPeng on 2017/6/25.
 */
public class LauncherScanUtil {

    private static final String ERROR_MESSAGE = "packageName can't be null";
    private static final String JAR_EXT = ".jar";
    private static final String JAR_DOT = "/";
    private static final String CLASS_EXT = ".class";
    private static final String DOT = ".";
    private static final String BLANK = "";

    /**
     * 扫描packages下面符合filter的class
     */
    public static  Set<Class<?>> scanPackages(String[] packages, ClassFilter filter) {
        checkPackagesName(packages);
        final String[] classPathArray = getClassPath();

        //用于保存class的集合
        Set<Class<?>> classList = new LinkedHashSet<>();

        //循环packageckasspath下的符合package的类
        for (String filePath : classPathArray) {
            scanRootFilePath(new File(filePath), packages, filter, classList);
        }

        return classList;
    }

    /**
     * 扫描单个jar或者文件夹下的类
     */
    private static void scanRootFilePath(File file, String[] packages, ClassFilter filter,   Set<Class<?>> classList) {
        String rootDirPath = null;
        if (isDirectory(file)) {
            rootDirPath = file.getAbsolutePath();
            //读取文件夹的文件
            processDirectory(file, packages, filter, classList,rootDirPath);
        }else if (isJarFile(file.getName())) {
            processJarFile(file, packages, filter, classList);
        }

    }

    /**
     * 扫描单个jar或者文件夹下的类
     */
    private static void scanFilePath(File file, String[] packages, ClassFilter filter,   Set<Class<?>> classList,String rootDir) {
        if (isDirectory(file)) {
            //读取文件夹的类
            processDirectory(file, packages, filter, classList,rootDir);
        }else if (isClass(file.getName())) {
            processClass(file, packages, filter, classList,rootDir);
        }

    }

    private static void processClass(File file, String[] packages, ClassFilter filter,  Set<Class<?>> classList,String rootDir) {
        //去掉根路径
        final String className = file.getAbsolutePath().replace(rootDir+File.separator,"").replace(File.separator, DOT).replace(CLASS_EXT, BLANK);
        addClass(className, packages, filter, classList);
    }

    private static void processJarFile(File file, String[] packages, ClassFilter filter,   Set<Class<?>> classList) {
        //读取jar时使用JarFile解压
        try {
//            new ZipFile(file);
            JarFile jarFile = new JarFile(file);
            Enumeration<JarEntry> entries = jarFile.entries();
            
            while(entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (isClass(entry.getName())) {
                    //将分隔符换成java的“.”
                    String className = entry.getName().replace(JAR_DOT, DOT).replace(CLASS_EXT, BLANK);
                    addClass(className, packages, filter, classList);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void addClass(String className, String[] packages, ClassFilter filter,  Set<Class<?>> classList) {

        if (packages != null && packages.length > 0) {
            for (int i = 0; i < packages.length; i++) {
                String packWithDot = packages[i] + DOT;
                if (checkClassName(className, packWithDot)) {
                    Class<?> aClass = null;
                    try {
                        filter.accept(aClass = Class.forName(className, false, ClassUtils.getClassLoader()));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    classList.add(aClass);
                    break;
                }
            }
        } else {
//            classList.add(aClass);
        }
    }

    private static boolean checkClassName(String className, String pack) {
        return className.indexOf(pack) == 0;
    }

    private static void processDirectory(File file, String[] packages, ClassFilter filter,  Set<Class<?>> classList,String rootDir) {
        for (File f : file.listFiles()) {
            scanFilePath(f, packages, filter, classList,rootDir);
        }
    }

    private static boolean isClass(String file) {
        return file.endsWith(CLASS_EXT);
    }

    private static boolean isJarFile(String file) {
        return file.endsWith(JAR_EXT);
    }

    private static boolean isDirectory(File file) {
        return file.isDirectory();
    }


    private static void checkPackagesName(String[] packages) {
        if (packages == null || packages.length == 0){
            throw new NullPointerException(ERROR_MESSAGE);
        }
    }

    /**
     * 获取classPath下所有的引用的java类（包括jar和文件夹）所在的路径
     */
    private static String[] getClassPath() {
        /* 包括 jre
        return System.getProperty("java.class.path").
               concat(System.getProperty("path.separator")).
               concat(System.getProperty("java.home")).
               split(System.getProperty("path.separator"));*/
        return System.getProperty("java.class.path").split(System.getProperty("path.separator"));

    }

}
